package controller

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/hex"
	"gdfs-service/conf"
	"gdfs-service/constant"
	"gdfs-service/controller/vo"
	"gdfs-service/db"
	"gdfs-service/logcat"
	"gdfs-service/socket"
	"github.com/gin-gonic/gin"
	"log"
	"math/big"
	"os"
	"strconv"
	"strings"
	"time"
)

// @Summary 旧文件上传接口没有FileType
// @Description 旧文件上传接口没有FileType
// @Accept multipart/form-data
// @Param files formData  string true "要上传的文件"
// @Param flag formData  string false "标志"
// @Param taskId formData  string false "任务id"
// @Param fileParentId formData  string false "文件父id"
// @Tags 文件上传下载接口
// @Success 200 {object} Result
// @Router /uploadFile [post]
func UploadFile(c *gin.Context) {
	log.Println("#########-------------------------------接收到文件上传------------------------------------------")
	c.Writer.Header().Set("content-type", "application/json")
	var uploadvo vo.UploadVo
	result := vo.NewResultInstance()
	err := c.Request.ParseMultipartForm(30)
	if err != nil {
		logcat.Info(err)
		return
	}
	srcfile, srcfileheader, err := c.Request.FormFile("files") // file 是上传表单域的名字
	if err != nil {
		uploadvo.FileKey = ""
		uploadvo.Flag = ""
		uploadvo.TaskId = ""
		result.Fail(constant.BussinessErrorType[constant.NOTVALID_ERROR], constant.NOTVALID_ERROR, uploadvo)
		WriteString(c.Writer, result)
		return
	}
	flag := c.Request.FormValue("flag")
	taskId := c.Request.FormValue("taskId")
	logcat.Info("#########----taskId", taskId, "// flag =", flag)
	if srcfile == nil || srcfileheader.Size == 0 {
		uploadvo.FileKey = ""
		uploadvo.Flag = ""
		uploadvo.TaskId = ""
		result.Fail(constant.BussinessErrorType[constant.NOTVALID_ERROR], constant.NOTVALID_ERROR, uploadvo)
		WriteString(c.Writer, result)
		return
	}
	defer srcfile.Close()
	logcat.Info("####文件大小:", srcfileheader.Size)
	if (conf.GetMaxSize() * 1024) < int(srcfileheader.Size)/1024 {
		uploadvo.FileKey = ""
		uploadvo.Flag = ""
		uploadvo.TaskId = ""
		result.Fail(constant.BussinessErrorType[constant.UPLOADFILE_SIZE_ERROR], constant.UPLOADFILE_SIZE_ERROR, uploadvo)
		WriteString(c.Writer, result)
		return
	}
	//获取文件后缀名位置
	index := strings.LastIndex(srcfileheader.Filename, ".")
	//获取文件后缀名
	subfix := srcfileheader.Filename[index:]
	//生成本地存储的文件名
	localFileName := strconv.FormatInt(time.Now().UnixNano(), 10) + CreateRandomString(8) + subfix
	date := time.Now().Format("2006-01-02")
	storagePath := conf.GetStorePath() + date + "/"
	_, fileErr := os.Stat(storagePath)
	if os.IsNotExist(fileErr) {
		//文件夹不存在创建
		createErr := os.Mkdir(storagePath, os.ModePerm)
		if createErr != nil {
			logcat.Info("###创建文件异常:", createErr)
			result.Fail(constant.BussinessErrorType[constant.SAVEFILEFAIL], constant.SAVEFILEFAIL, createErr)
			WriteString(c.Writer, result)
			return
		}
	}
	if err = c.SaveUploadedFile(srcfileheader, storagePath+localFileName); err != nil {
		uploadvo.FileKey = ""
		uploadvo.Flag = ""
		uploadvo.TaskId = ""
		result.Fail(constant.BussinessErrorType[constant.SAVEFILEFAIL], constant.SAVEFILEFAIL, err)
		WriteString(c.Writer, result)
		return
	}
	logcat.Info("文件路径:", storagePath+localFileName)
	fi, errr := os.Stat(storagePath + localFileName)
	if errr != nil {
		result.Fail(constant.BussinessErrorType[constant.SAVEFILEFAIL], "打开文件详细信息失败", uploadvo)
		WriteString(c.Writer, result)
		return
	}
	log.Println("###文件名", localFileName)
	//md5数字签名
	sgin := md5.Sum([]byte(localFileName))
	filekey := conf.GetStoreid() + hex.EncodeToString(sgin[:])
	log.Println("##MD5文件签名", filekey)
	//数据组装
	var fileInfo db.FileInfo
	fileInfo.FileKey = filekey
	fileInfo.FileOriginalName = srcfileheader.Filename
	logcat.Info("####原文件名:", srcfileheader.Filename, "本地文件名:", localFileName)
	fileInfo.FileName = localFileName
	fileInfo.FilePath = "/" + date + "/"
	fileInfo.FileSize = strconv.FormatInt(fi.Size(), 10)
	fileInfo.FileSuffixName = subfix
	//存入数据库
	if socket.GetNodeConf().NodeID == "" {
		fileInfo.SyncStatus = "Y"
	}
	dberr := db.GetDB().Create(&fileInfo).Error
	if dberr != nil {
		//存入数据失败
		logcat.Info("####文件上传失败:", dberr)
		uploadvo.FileKey = ""
		uploadvo.Flag = ""
		uploadvo.TaskId = "'"
		result.Fail(constant.BussinessErrorType[constant.SAVEFILEFAIL], constant.SAVEFILEFAIL, uploadvo)
		WriteString(c.Writer, result)
		return
	}
	logcat.Info("#########--------数据库中的文件秘钥:", fileInfo.FileKey, "储存的文件名称:", fileInfo.FileName)
	uploadvo.FileKey = fileInfo.FileKey
	uploadvo.Flag = flag
	uploadvo.TaskId = taskId
	uploadvo.UploadSize = fileInfo.FileSize
	result.SucessDefault(uploadvo)
	WriteString(c.Writer, result)
	var updateSync socket.UpdateSync
	updateSync.FileKey = filekey
	if socket.GetNodeConf().NodeID != "" {
		socket.SyncUpdateChan <- updateSync
	}
}

func CreateRandomString(len int) string {
	var container string
	var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
	b := bytes.NewBufferString(str)
	length := b.Len()
	bigInt := big.NewInt(int64(length))
	for i := 0; i < len; i++ {
		randomInt, _ := rand.Int(rand.Reader, bigInt)
		container += string(str[randomInt.Int64()])
	}
	return container
}
